﻿/*
   Open Intel 
   Copyright © 2011 – ISC. All Rights Reserved.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Controls;
using Caliburn.Micro;
using OI;
using OI.Async;
using OI.DataModel;
using OI.Framework;
using OIManager.Async;
using OIManager.Events;
using OIManager.Views;


namespace OIManager.ViewModels
{
    [Export(typeof(SetupAppsViewModel))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class SetupAppsViewModel : Screen, IHandle<ActivateJurisdiction>
    {
        #region DATA
        readonly IEventAggregator Events;
        public DataForm DetailsForm { get; private set; }
        public bool UpdatingApp { get; set; }

        // all items
        public BindableCollection<OIApp> Items
        {
            get 
            {
                return _Items ?? (_Items = new BindableCollection<OIApp>()); 
            }
            private set 
            { 
                _Items = value;
                NotifyOfPropertyChange(() => Items);

                // select the first item if the collection is reset
                if (_Items != null && _Items.Count > 0)
                {
                    Item = _Items[0];
                }
                
                CanAddApp = true;
            }
        }
        private BindableCollection<OIApp> _Items;

        // selected item in catalog
        public OIApp Item
        {
            get
            {
                return _Item;
            }
            set
            {
                var oldVal = _Item;
                _Item = value;

                // only update UI on change
                if (_Item != oldVal && _Item != null)
                {
                    NotifyOfPropertyChange(() => Item);
                    NotifyOfPropertyChange(() => CanRemApp);
                }
            }
        }
        private OIApp _Item;


        // by convention
        public bool CanRemApp
        {
            get
            {
                return Item != null && Items.Count > 0;
            }
        }


        // by convention
        public bool CanAddApp
        {
            get { return _CanAddApp; }
            set 
            { 
                _CanAddApp = value;
                NotifyOfPropertyChange(() => CanAddApp);
            }
        }
        private bool _CanAddApp;
        #endregion


        [ImportingConstructor]
        public SetupAppsViewModel(IEventAggregator events)
		{
            Events = events;
			events.Subscribe(this);
		}


        protected override void OnViewLoaded(object view)
        {
            base.OnViewLoaded(view);

            // get the details DataForm
            DetailsForm = ((SetupAppsView)view).DetailsForm;
            DetailsForm.BeginningEdit += DetailsFormBeginningEdit;
            DetailsForm.EditEnded += DetailsFormEditEnded;

            if (Items.Count == 0)
            {
                Coroutine.BeginExecute(LoadApps());
            }
        }


        // coroutine for async download of all apps
        // we cache locally and filter client-side
        public IEnumerator<IResult> LoadApps()
        {
            IoC.Get<IShell>().Busy(true, "loading apps...");

            var dsq = new CatalogQuery<OIApp>(Configuration.Jurisdiction.ID);
            yield return dsq;

            Items = new BindableCollection<OIApp>(dsq.Results);

            IoC.Get<IShell>().Busy(false);
        }


        public void Handle(ActivateJurisdiction message)
        {
            Items.Clear();
        }


        // DataForm edit begin
        private void DetailsFormBeginningEdit(object sender, System.ComponentModel.CancelEventArgs e)
        {
            // set validation function
            Item.PostValidationFunction = null;
        }


        // DataForm edit ended
        private void DetailsFormEditEnded(object sender, DataFormEditEndedEventArgs e)
        {
            if (e.EditAction == DataFormEditAction.Commit && !UpdatingApp)
            {
                 Coroutine.BeginExecute(SetApp(Item));
            }
            CanAddApp = true;
        }


        // coroutine for async update of an app
        public IEnumerator<IResult> SetApp(OIApp app)
        {
            IoC.Get<IShell>().Busy(true, "updating app...");
            UpdatingApp = true;

            var svm =  IoC.Get<SettingsViewModel>();
            var au = new AppUpdate(app, svm.SQLConnection);
            yield return au;

            if (!string.IsNullOrEmpty(au.Results))
            {
                IoC.Get<IShell>().HandleException(new Exception(au.Results), "Update app failed");
            }
            else
            {
                // reload to get new ID and sort order
                var dsq = new CatalogQuery<OIApp>(Configuration.Jurisdiction.ID);
                yield return dsq;

                foreach (var item in dsq.Results)
                {
                    if (item.ShareID == app.ShareID)
                    {
                        app.ID = item.ID;
                        break;
                    }
                }
                Items.Refresh();
            }

            UpdatingApp = false;
            IoC.Get<IShell>().Busy(false);
        }


        // coroutine for async delete of an app
        public IEnumerator<IResult> RemoveApp(int appID)
        {
            IoC.Get<IShell>().Busy(true, "deleting app...");

            var svm = IoC.Get<SettingsViewModel>();
            var ad = new AppRemove(appID, svm.SQLConnection);
            yield return ad;

            IoC.Get<IShell>().Busy(false);

            if (!string.IsNullOrEmpty(ad.Results))
            {
                IoC.Get<IShell>().HandleException(new Exception(ad.Results), "Delete app failed");
            }
            else
            {
                DetailsForm.DeleteItem();
            }

            NotifyOfPropertyChange(() => CanRemApp);
        }
       

        // by convention
        public void AddApp()
        {
            var nI = new OIApp();
            Items.Add(nI);
            Item = nI;

            // begin/cancel flushes any previous validation errors
            DetailsForm.BeginEdit();
            DetailsForm.CancelEdit();
            DetailsForm.BeginEdit();

            // make sure new record has jurisdiction FK (since this is not editable)
            Item.JurisdictionFK = Configuration.Jurisdiction.ID;

            // this is a new item, add a validation action to make sure added item doesn't use the same title
            var names = Items.Select(i => i.Title).ToList();
            Item.PostValidationFunction = (app, colName) =>
            {
                if (colName == "Title")
                {
                    if (names.Any(n => n.ToLower() == app.Title.ToLower()))
                    {
                        return "is already in use, please select a different title";
                    }
                }
                return null;
            };

            CanAddApp = false;
        }


        // by convention
        public void RemApp()
        {
            if (Item != null)
            {
                System.Action remAction = () =>  Coroutine.BeginExecute(RemoveApp(Item.ID));

                var dialog = new MessageBoxViewModel(true, remAction)
                {
                    DisplayName = "Remove App",
                    Message = "Are you sure you want to remove " + Item.Title + " ?"
                };

                IoC.Get<IWindowManager>().ShowDialog(dialog);
            }
        }
    }
}
